<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>摩托车活塞 - 3D 模型查看器</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            width: 100%;
            height: 100vh;
            overflow: hidden;
            background: linear-gradient(135deg, #0a1929 0%, #1a237e 50%, #283593 100%);
            background-attachment: fixed;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
            position: relative;
        }

        body::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-image: 
                linear-gradient(rgba(33, 150, 243, 0.1) 1px, transparent 1px),
                linear-gradient(90deg, rgba(33, 150, 243, 0.1) 1px, transparent 1px);
            background-size: 50px 50px;
            pointer-events: none;
            animation: gridMove 20s linear infinite;
            z-index: 0;
        }

        @keyframes gridMove {
            0% { transform: translate(0, 0); }
            100% { transform: translate(50px, 50px); }
        }

        body::after {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: radial-gradient(circle, rgba(33, 150, 243, 0.15) 0%, transparent 70%);
            animation: rotate 20s linear infinite;
            pointer-events: none;
            z-index: 0;
        }

        @keyframes rotate {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        #canvas-container {
            width: 100%;
            height: 100%;
            position: relative;
            z-index: 1;
        }

        #loading {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: white;
            font-size: 18px;
            z-index: 100;
            text-align: center;
        }

        .loading-spinner {
            border: 4px solid rgba(255, 255, 255, 0.3);
            border-top: 4px solid white;
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 0 auto 20px;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        #controls {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(0, 0, 0, 0.5);
            padding: 15px 25px;
            border-radius: 25px;
            color: white;
            font-size: 14px;
            z-index: 10;
            backdrop-filter: blur(10px);
        }

        #controls p {
            margin: 5px 0;
        }

        .hidden {
            display: none;
        }

        /* 引导线画布 */
        #guide-line-canvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            z-index: 10;
        }

        /* 信息文本框 */
        #info-box {
            position: absolute;
            right: 50px;
            top: 50%;
            transform: translateY(-50%);
            width: 350px;
            min-height: 150px;
            padding: 20px;
            background: rgba(10, 25, 41, 0.9);
            border: 2px solid #00bfff;
            border-radius: 8px;
            color: white;
            font-size: 16px;
            line-height: 1.8;
            box-shadow: 0 4px 20px rgba(0, 191, 255, 0.3);
            z-index: 20;
            display: none;
            backdrop-filter: blur(10px);
        }

        #info-box.show {
            display: block;
            animation: fadeIn 0.3s ease-in;
        }

        @keyframes fadeIn {
            from {
                opacity: 0;
                transform: translateY(-50%) translateX(20px);
            }
            to {
                opacity: 1;
                transform: translateY(-50%) translateX(0);
            }
        }

        #info-box-title {
            font-size: 20px;
            font-weight: bold;
            margin-bottom: 15px;
            color: #00bfff;
            border-bottom: 1px solid rgba(0, 191, 255, 0.3);
            padding-bottom: 10px;
        }

        #info-box-content {
            color: #ffffff;
        }

        /* Tab 组件样式 */
        #tab-container {
            position: absolute;
            bottom: 80px;
            left: 50%;
            transform: translateX(-50%);
            width: 60%;
            max-width: 800px;
            z-index: 30;
        }

        .tab-wrapper {
            position: relative;
            overflow: visible;
            padding: 0 60px 0 120px;
        }

        .tab-scroll-container {
            display: flex;
            gap: 15px;
            overflow-x: auto;
            overflow-y: visible;
            scroll-behavior: smooth;
            scrollbar-width: none; /* Firefox */
            -ms-overflow-style: none; /* IE and Edge */
            padding: 20px 20px 10px 20px;
        }

        .tab-scroll-container::-webkit-scrollbar {
            display: none; /* Chrome, Safari, Opera */
        }

        .tab-item {
            flex: 0 0 auto;
            min-width: 120px;
            max-width: 200px;
            padding: 15px 25px;
            background: rgba(10, 25, 41, 0.85);
            border: 2px solid #00bfff;
            border-radius: 8px;
            color: #ffffff;
            font-size: 16px;
            text-align: center;
            cursor: pointer;
            transition: all 0.3s ease;
            position: relative;
            backdrop-filter: blur(10px);
            box-shadow: 0 2px 10px rgba(0, 191, 255, 0.2);
            user-select: none;
            overflow: hidden;
        }

        /* 科技感边框发光效果 */
        .tab-item::before {
            content: '';
            position: absolute;
            top: -2px;
            left: -2px;
            right: -2px;
            bottom: -2px;
            border-radius: 8px;
            background: linear-gradient(45deg, #00bfff, #00ffff, #00bfff, #00ffff);
            background-size: 300% 300%;
            opacity: 0;
            transition: opacity 0.3s ease;
            z-index: -1;
            animation: borderGlow 3s ease infinite;
        }

        .tab-item:hover::before {
            opacity: 0.6;
        }

        @keyframes borderGlow {
            0%, 100% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
        }

        /* 高亮状态 */
        .tab-item.active {
            border-color: #00ffff;
            background: rgba(0, 191, 255, 0.2);
            box-shadow: 0 0 20px rgba(0, 255, 255, 0.5), 0 2px 15px rgba(0, 191, 255, 0.4);
            transform: scale(1.05);
        }

        .tab-item.active::before {
            opacity: 1;
        }

        /* 点击放大动画 */
        .tab-item:active {
            transform: scale(1.1);
        }

        /* 科技感发光效果 */
        .tab-item::after {
            content: '';
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 0;
            height: 0;
            border-radius: 50%;
            background: radial-gradient(circle, rgba(0, 255, 255, 0.4) 0%, transparent 70%);
            transition: width 0.3s ease, height 0.3s ease;
            pointer-events: none;
        }

        .tab-item.active::after {
            width: 150%;
            height: 150%;
        }

        /* 左右滑动按钮 */
        .tab-scroll-btn {
            position: absolute;
            top: 50%;
            transform: translateY(-50%);
            width: 45px;
            height: 45px;
            background: rgba(10, 25, 41, 0.9);
            border: 2px solid #00bfff;
            border-radius: 50%;
            color: #00bfff;
            font-size: 20px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.3s ease;
            z-index: 10;
            backdrop-filter: blur(10px);
            box-shadow: 0 2px 10px rgba(0, 191, 255, 0.3);
        }

        .tab-scroll-btn:hover {
            background: rgba(0, 191, 255, 0.2);
            border-color: #00ffff;
            box-shadow: 0 0 15px rgba(0, 255, 255, 0.5);
            transform: translateY(-50%) scale(1.1);
        }

        .tab-scroll-btn:active {
            transform: translateY(-50%) scale(0.95);
        }

        .tab-scroll-btn.left {
            left: 0;
        }

        .tab-scroll-btn.right {
            right: 0;
        }

        .tab-scroll-btn.disabled {
            opacity: 0.3;
            cursor: not-allowed;
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div id="canvas-container">
        <div id="loading">
            <div class="loading-spinner"></div>
            <div>正在加载 3D 模型...</div>
        </div>
        <!-- 引导线画布 -->
        <canvas id="guide-line-canvas"></canvas>
        <!-- 信息文本框 -->
        <div id="info-box">
            <div id="info-box-title"></div>
            <div id="info-box-content"></div>
        </div>
    </div>

    <!-- Tab 组件 -->
    <div id="tab-container">
        <div class="tab-wrapper">
            <button class="tab-scroll-btn left" id="tab-scroll-left">‹</button>
            <div class="tab-scroll-container" id="tab-scroll-container">
                <!-- Tab items will be dynamically generated -->
            </div>
            <button class="tab-scroll-btn right" id="tab-scroll-right">›</button>
        </div>
    </div>

    <script type="importmap">
        {
            "imports": {
                "three": "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js",
                "three/addons/": "https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/"
            }
        }
    </script>

    <script type="module">
        import * as THREE from 'three';
        import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
        import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

        // 场景设置
        const scene = new THREE.Scene();
        scene.background = null; // 透明背景，显示页面背景

        // 相机设置
        const camera = new THREE.PerspectiveCamera(
            75,
            window.innerWidth / window.innerHeight,
            0.1,
            1000
        );
        camera.position.set(0, 0, 5);

        // 渲染器设置
        const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
        renderer.setSize(window.innerWidth, window.innerHeight);
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.shadowMap.enabled = true;
        renderer.shadowMap.type = THREE.PCFSoftShadowMap;
        document.getElementById('canvas-container').appendChild(renderer.domElement);

        // 轨道控制器
        const controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.dampingFactor = 0.05;
        
        // 保存上一次的相机位置和目标，用于检测变化
        let lastCameraPosition = camera.position.clone();
        let lastControlsTarget = controls.target.clone();

        // 灯光设置
        const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
        scene.add(ambientLight);

        const directionalLight1 = new THREE.DirectionalLight(0xffffff, 0.8);
        directionalLight1.position.set(5, 5, 5);
        directionalLight1.castShadow = true;
        scene.add(directionalLight1);

        const directionalLight2 = new THREE.DirectionalLight(0xffffff, 0.4);
        directionalLight2.position.set(-5, -5, -5);
        scene.add(directionalLight2);

        // 添加点光源增强效果
        const pointLight = new THREE.PointLight(0xffffff, 0.5);
        pointLight.position.set(0, 0, 10);
        scene.add(pointLight);

        // 射线检测器
        const raycaster = new THREE.Raycaster();
        const mouse = new THREE.Vector2();
        
        // 高亮管理
        let highlightedObject = null;
        let originalMaterials = new Map(); // 存储原始材质
        
        // 拖拽检测
        let mouseDownPosition = null;
        let isDragging = false;
        let isClicking = false; // 标记是否正在点击（用于区分点击和拖拽）
        let lastClickTime = 0; // 记录最后一次点击的时间

        // 引导线和信息框管理
        const guideLineCanvas = document.getElementById('guide-line-canvas');
        const guideLineCtx = guideLineCanvas.getContext('2d');
        const infoBox = document.getElementById('info-box');
        const infoBoxTitle = document.getElementById('info-box-title');
        const infoBoxContent = document.getElementById('info-box-content');

        // 初始化引导线画布
        function initGuideLineCanvas() {
            guideLineCanvas.width = window.innerWidth;
            guideLineCanvas.height = window.innerHeight;
            guideLineCtx.strokeStyle = '#00bfff';
            guideLineCtx.lineWidth = 2;
            guideLineCtx.lineCap = 'round';
            guideLineCtx.lineJoin = 'round';
        }
        initGuideLineCanvas();

        // ============================================
        // 部位信息系统配置
        // ============================================
        // 部位信息数据字典（可以根据实际模型部位名称进行配置）
        const partInfo = {
            // 默认信息，可以根据模型中的实际对象名称进行匹配
            'default': {
                title: '活塞部位',
                content: '这是活塞的一个组成部分，具有重要的功能和作用。'
            },
            // 摩托车活塞各部位详细信息
            'piston_crown': {
                title: '活塞顶面',
                content: '活塞顶面是燃烧室重要组成部分，直接承受燃气燃烧产生的高温高压，其形状需精准契合发动机燃烧室结构，以保障燃烧效率与动力输出。顶面设计直接影响燃烧室内的气流运动，对发动机的性能和排放具有决定性影响。'
            },
            'valve_relief': {
                title: '气门避让坑',
                content: '气门避让坑是活塞顶部为气门运动预留的空间，防止气门与活塞发生碰撞，确保发动机正常运转，其深度和形状需根据气门运动轨迹精确设计。避让坑的设计直接影响发动机的压缩比和燃烧效率。'
            },
            'installation_mark': {
                title: '装机标识',
                content: '装机标识用于指示活塞的正确安装方向，确保活塞在气缸中的正确位置，避免因安装错误导致的发动机故障，是装配过程中的重要参考标记。正确的安装方向对发动机的性能和寿命至关重要。'
            },
            'oil_hole': {
                title: '油孔',
                content: '油孔用于润滑油的流通，确保活塞与气缸壁之间的润滑效果，减少摩擦磨损，提高发动机效率和使用寿命，其位置和尺寸需精确设计。油孔的设计直接影响发动机的润滑性能和散热效果。'
            },
            'piston_skirt': {
                title: '活塞裙部',
                content: '活塞裙部是活塞的主要支撑部分，与气缸壁直接接触，承受侧向力，其表面处理和尺寸精度直接影响发动机的运行平稳性和密封性能。裙部设计需要充分考虑热膨胀和机械强度，确保活塞在高温高压环境下仍能保持稳定的运动轨迹。'
            }
        };

        // 对象名称到部位名称的映射表（用于匹配模型中的对象名称）
        const objectNameMapping = {
            'piston-crown': 'piston_crown',
            'pistoncrown': 'piston_crown',
            'crown': 'piston_crown',
            'valve-relief': 'valve_relief',
            'valverelief': 'valve_relief',
            'installation-mark': 'installation_mark',
            'installationmark': 'installation_mark',
            'oil-hole': 'oil_hole',
            'oilhole': 'oil_hole',
            'piston-skirt': 'piston_skirt',
            'pistonskirt': 'piston_skirt',
            'skirt': 'piston_skirt'
        };

        // Tab 组件管理
        const tabContainer = document.getElementById('tab-scroll-container');
        const tabScrollLeft = document.getElementById('tab-scroll-left');
        const tabScrollRight = document.getElementById('tab-scroll-right');
        let currentActiveTab = null;
        const visibleTabsCount = 5; // 最多显示5个tab

        // 从 partInfo 中提取所有部位名称（排除 'default'）
        function getPartNames() {
            return Object.keys(partInfo)
                .filter(key => key !== 'default')
                .map(key => partInfo[key].title);
        }

        // 初始化 Tab 组件
        function initTabs() {
            const partNames = getPartNames();
            
            // 清空现有 tab
            tabContainer.innerHTML = '';
            
            // 创建 tab 项
            partNames.forEach((name, index) => {
                const tabItem = document.createElement('div');
                tabItem.className = 'tab-item';
                tabItem.textContent = name;
                tabItem.dataset.index = index;
                tabItem.addEventListener('click', () => handleTabClick(tabItem, index));
                tabContainer.appendChild(tabItem);
            });
            
            // 初始化滚动按钮状态
            updateScrollButtons();
            
            // 监听滚动事件，更新按钮状态
            tabContainer.addEventListener('scroll', updateScrollButtons);
        }

        // 处理 Tab 点击
        function handleTabClick(tabItem, index) {
            // 移除之前的高亮
            if (currentActiveTab) {
                currentActiveTab.classList.remove('active');
            }
            
            // 添加点击动画效果
            tabItem.style.transform = 'scale(1.1)';
            setTimeout(() => {
                tabItem.style.transform = '';
            }, 150);
            
            // 设置新的高亮
            tabItem.classList.add('active');
            currentActiveTab = tabItem;
            
            // 根据 index 找到对应的部位 key
            const partKeys = Object.keys(partInfo).filter(key => key !== 'default');
            if (partKeys[index]) {
                const partKey = partKeys[index];
                // 高亮对应的部位（这里需要根据实际情况实现）
                console.log('点击了 Tab:', tabItem.textContent, '部位key:', partKey);
            }
        }

        // 更新滚动按钮状态
        function updateScrollButtons() {
            const container = tabContainer;
            const scrollLeft = container.scrollLeft;
            const scrollWidth = container.scrollWidth;
            const clientWidth = container.clientWidth;
            
            // 左侧按钮：如果滚动位置为0，禁用
            if (scrollLeft <= 0) {
                tabScrollLeft.classList.add('disabled');
            } else {
                tabScrollLeft.classList.remove('disabled');
            }
            
            // 右侧按钮：如果已滚动到底部，禁用
            if (scrollLeft + clientWidth >= scrollWidth - 1) {
                tabScrollRight.classList.add('disabled');
            } else {
                tabScrollRight.classList.remove('disabled');
            }
        }

        // 滚动 Tab 容器
        function scrollTabs(direction) {
            const container = tabContainer;
            const scrollAmount = 300; // 每次滚动的距离
            const currentScroll = container.scrollLeft;
            
            if (direction === 'left') {
                container.scrollTo({
                    left: currentScroll - scrollAmount,
                    behavior: 'smooth'
                });
            } else {
                container.scrollTo({
                    left: currentScroll + scrollAmount,
                    behavior: 'smooth'
                });
            }
        }

        // 绑定滚动按钮事件
        tabScrollLeft.addEventListener('click', () => scrollTabs('left'));
        tabScrollRight.addEventListener('click', () => scrollTabs('right'));

        // 初始化 Tab
        initTabs();

        // 当前引导线状态
        let currentGuideLineState = null;

        // 清除引导线
        function clearGuideLine() {
            guideLineCtx.clearRect(0, 0, guideLineCanvas.width, guideLineCanvas.height);
        }

        // 绘制起点高亮点（科技感）
        function drawStartPointHighlight(x, y) {
            const radius = 12; // 核心半径
            const glowRadius = 20; // 光晕半径
            
            // 创建径向渐变（从中心到外围）
            const gradient = guideLineCtx.createRadialGradient(x, y, 0, x, y, glowRadius);
            gradient.addColorStop(0, 'rgba(0, 191, 255, 1)'); // 中心：亮蓝色
            gradient.addColorStop(0.4, 'rgba(0, 191, 255, 0.8)'); // 中间：半透明蓝
            gradient.addColorStop(0.7, 'rgba(0, 191, 255, 0.3)'); // 外围：更透明
            gradient.addColorStop(1, 'rgba(0, 191, 255, 0)'); // 最外围：完全透明
            
            // 绘制外圈光晕
            guideLineCtx.save();
            guideLineCtx.beginPath();
            guideLineCtx.arc(x, y, glowRadius, 0, Math.PI * 2);
            guideLineCtx.fillStyle = gradient;
            guideLineCtx.fill();
            
            // 绘制核心亮点（实心圆）
            guideLineCtx.beginPath();
            guideLineCtx.arc(x, y, radius, 0, Math.PI * 2);
            guideLineCtx.fillStyle = '#00bfff';
            guideLineCtx.fill();
            
            // 绘制内圈（更亮的中心）
            guideLineCtx.beginPath();
            guideLineCtx.arc(x, y, radius * 0.5, 0, Math.PI * 2);
            guideLineCtx.fillStyle = '#ffffff';
            guideLineCtx.fill();
            
            // 绘制外圈边框（科技感）
            guideLineCtx.beginPath();
            guideLineCtx.arc(x, y, radius, 0, Math.PI * 2);
            guideLineCtx.strokeStyle = '#00ffff';
            guideLineCtx.lineWidth = 1.5;
            guideLineCtx.stroke();
            
            guideLineCtx.restore();
        }

        // 绘制引导线（支持直线和带拐角的线）
        function drawGuideLine(startX, startY, endX, endY, useCorner = true, cornerType = 'right') {
            clearGuideLine();
            
            // 先绘制起点高亮点
            drawStartPointHighlight(startX, startY);
            
            if (!useCorner) {
                // 直线
                guideLineCtx.beginPath();
                guideLineCtx.moveTo(startX, startY);
                guideLineCtx.lineTo(endX, endY);
                guideLineCtx.stroke();
            } else {
                // 带拐角的引导线
                const cornerDistance = 80; // 拐点距离终点的距离
                let cornerX, cornerY;
                
                if (startX < endX) {
                    // 起点在终点左边，向右延伸
                    cornerX = endX - cornerDistance;
                    cornerY = startY;
                } else {
                    // 起点在终点右边，向左延伸
                    cornerX = endX + cornerDistance;
                    cornerY = startY;
                }
                
                guideLineCtx.beginPath();
                guideLineCtx.moveTo(startX, startY);
                guideLineCtx.lineTo(cornerX, cornerY);
                guideLineCtx.lineTo(endX, endY);
                guideLineCtx.stroke();
            }
        }

        // 更新引导线（根据当前状态重新绘制）
        function updateGuideLine() {
            if (currentGuideLineState && highlightedObject) {
                // 获取对象的边界框中心点（使用世界坐标）
                const box = new THREE.Box3().setFromObject(highlightedObject);
                const centerPoint = new THREE.Vector3();
                box.getCenter(centerPoint);
                
                // 将世界坐标转换为屏幕坐标
                const vector = centerPoint.clone().project(camera);
                const screenX = (vector.x + 1) * window.innerWidth / 2;
                const screenY = (-vector.y + 1) * window.innerHeight / 2;
                
                // 信息框位置
                const endX = window.innerWidth - 50 - 350;
                const endY = window.innerHeight / 2;
                
                // 更新并绘制引导线
                currentGuideLineState.startX = screenX;
                currentGuideLineState.startY = screenY;
                drawGuideLine(screenX, screenY, endX, endY, currentGuideLineState.useCorner, currentGuideLineState.cornerType);
            }
        }

        // 显示信息框
        function showInfoBox(title, content) {
            infoBoxTitle.textContent = title;
            infoBoxContent.textContent = content;
            infoBox.classList.add('show');
        }

        // 隐藏信息框
        function hideInfoBox() {
            infoBox.classList.remove('show');
        }

        // 获取部位信息（根据对象名称匹配）
        function getPartInfo(object) {
            // 0. 首先检查手动配置的对象到部位的直接映射（优先级最高）
            let currentObject = object;
            let checkDepth = 0;
            const maxCheckDepth = 3; // 最多向上查找3层
            
            while (currentObject && checkDepth < maxCheckDepth) {
                if (objectToPartMap.has(currentObject)) {
                    const partKey = objectToPartMap.get(currentObject);
                    if (partInfo[partKey]) {
                        return partInfo[partKey];
                    }
                }
                currentObject = currentObject.parent;
                checkDepth++;
            }
            
            // 尝试从对象本身及其父对象获取名称
            currentObject = object;
            let objectName = '';
            let searchDepth = 0;
            const maxDepth = 3; // 最多向上查找3层
            
            // 向上查找有名称的对象
            while (currentObject && searchDepth < maxDepth) {
                if (currentObject.name && currentObject.name.trim() !== '') {
                    objectName = currentObject.name;
                    break;
                }
                currentObject = currentObject.parent;
                searchDepth++;
            }
            
            if (!objectName) {
                return partInfo.default;
            }
            
            const lowerName = objectName.toLowerCase().replace(/-/g, '_');
            
            // 1. 检查名称映射表
            if (objectNameMapping[lowerName]) {
                const mappedKey = objectNameMapping[lowerName];
                if (partInfo[mappedKey]) {
                    return partInfo[mappedKey];
                }
            }
            
            // 2. 尝试直接匹配对象名称（精确匹配）
            if (partInfo[lowerName]) {
                return partInfo[lowerName];
            }
            
            // 3. 尝试部分匹配（对象名称包含部位key）
            for (const [key, info] of Object.entries(partInfo)) {
                if (key !== 'default') {
                    const keyLower = key.toLowerCase();
                    if (lowerName.includes(keyLower) || keyLower.includes(lowerName)) {
                        return info;
                    }
                }
            }
            
            // 4. 如果对象名称包含中文关键词，尝试匹配
            const chineseKeywords = {
                '顶面': 'piston_crown',
                '顶部': 'piston_crown',
                '顶': 'piston_crown',
                '避让': 'valve_relief',
                '气门': 'valve_relief',
                '标识': 'installation_mark',
                '安装': 'installation_mark',
                '油孔': 'oil_hole',
                '油': 'oil_hole',
                '孔': 'oil_hole',
                '裙部': 'piston_skirt',
                '裙': 'piston_skirt'
            };
            
            for (const [keyword, partKey] of Object.entries(chineseKeywords)) {
                if (objectName.includes(keyword) && partInfo[partKey]) {
                    return partInfo[partKey];
                }
            }
            
            // 5. 如果没有匹配到，返回默认信息
            return partInfo.default;
        }
        
        // 高亮函数
        function highlightObject(object) {
            // 清除之前的高亮
            if (highlightedObject) {
                restoreOriginalMaterial(highlightedObject);
            }
            
            // 保存原始材质并应用高亮
            highlightedObject = object;
            saveAndHighlightMaterial(object);
        }
        
        // 保存原始材质并应用高亮
        function saveAndHighlightMaterial(object) {
            if (!object.material) return;
            
            // 保存原始材质引用（如果还没有保存）
            if (!originalMaterials.has(object)) {
                originalMaterials.set(object, {
                    material: object.material,
                    isArray: Array.isArray(object.material)
                });
            }
            
            // 为这个对象创建独立的材质副本，避免影响其他共享相同材质的对象
            if (Array.isArray(object.material)) {
                // 材质数组
                object.material = object.material.map(mat => {
                    const clonedMat = mat.clone();
                    clonedMat.emissive = new THREE.Color(0x00ff00); // 绿色高亮
                    clonedMat.emissiveIntensity = 0.5;
                    clonedMat.needsUpdate = true;
                    return clonedMat;
                });
            } else {
                // 单个材质
                const clonedMat = object.material.clone();
                clonedMat.emissive = new THREE.Color(0x00ff00); // 绿色高亮
                clonedMat.emissiveIntensity = 0.5;
                clonedMat.needsUpdate = true;
                object.material = clonedMat;
            }
        }
        
        // 恢复原始材质
        function restoreOriginalMaterial(object) {
            if (!originalMaterials.has(object)) return;
            
            const savedMaterial = originalMaterials.get(object);
            // 恢复原始材质引用
            object.material = savedMaterial.material;
            
            originalMaterials.delete(object);
        }
        
        // 清除高亮
        function clearHighlight() {
            if (highlightedObject) {
                restoreOriginalMaterial(highlightedObject);
                highlightedObject = null;
            }
            clearGuideLine();
            hideInfoBox();
            currentGuideLineState = null;
        }

        // 对象到部位的直接映射（用于手动指定对象对应的部位）
        const objectToPartMap = new Map();

        // 手动配置模型部位映射的函数
        function configureModelParts(root, nameToPartMap) {
            // 遍历场景中的所有对象
            root.traverse((child) => {
                if (child.isMesh || child.isGroup) {
                    const name = child.name;
                    if (name && nameToPartMap[name]) {
                        const partKey = nameToPartMap[name];
                        objectToPartMap.set(child, partKey);
                        console.log(`已配置部位: ${name} -> ${partInfo[partKey]?.title || partKey}`);
                    }
                }
            });
        }

        // 加载 GLTF 模型
        const loader = new GLTFLoader();
        loader.load(
            './摩托车活塞.gltf',
            function(gltf) {
                const model = gltf.scene;
                
                // 计算模型边界框并居中
                const box = new THREE.Box3().setFromObject(model);
                const center = box.getCenter(new THREE.Vector3());
                const size = box.getSize(new THREE.Vector3());
                
                // 居中模型
                model.position.x -= center.x;
                model.position.y -= center.y;
                model.position.z -= center.z;
                
                // 根据模型大小调整相机位置
                const maxDim = Math.max(size.x, size.y, size.z);
                const fov = camera.fov * (Math.PI / 180);
                let cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2));
                cameraZ *= 1.5;
                camera.position.set(cameraZ, cameraZ, cameraZ);
                camera.lookAt(0, 0, 0);
                controls.update();

                scene.add(model);
                
                // 手动配置模型部位映射（如果需要）
                // 取消注释下面的代码并根据实际模型对象名称进行配置
                // configureModelParts(model, {
                //     'Piston_Crown': 'piston_crown',
                //     'Valve_Relief': 'valve_relief',
                //     'Installation_Mark': 'installation_mark',
                //     'Oil_Hole': 'oil_hole',
                //     'Piston_Skirt': 'piston_skirt'
                // });
                
                // 输出模型中的所有对象名称，帮助用户配置
                console.log('=== 模型对象列表 ===');
                const objectNames = [];
                model.traverse((child) => {
                    if (child.isMesh || child.isGroup) {
                        if (child.name && child.name.trim() !== '') {
                            objectNames.push(child.name);
                        }
                    }
                });
                if (objectNames.length > 0) {
                    console.log('模型中的对象名称:', objectNames);
                    console.log('提示: 可以在 configureModelParts 函数中配置这些对象的部位映射');
                } else {
                    console.log('模型中的对象没有名称，需要手动配置或使用默认匹配');
                }
                console.log('==================');
                
                // 隐藏加载提示
                document.getElementById('loading').classList.add('hidden');
            },
            function(xhr) {
                const percentComplete = (xhr.loaded / xhr.total) * 100;
                console.log('加载进度: ' + percentComplete.toFixed(2) + '%');
            },
            function(error) {
                console.error('加载模型出错:', error);
                document.getElementById('loading').innerHTML = 
                    '<div style="color: #ff6b6b;">❌ 加载失败，请检查文件路径</div>';
            }
        );

        // 鼠标按下事件
        function onMouseDown(event) {
            mouseDownPosition = {
                x: event.clientX,
                y: event.clientY
            };
            isDragging = false;
        }
        
        // 鼠标移动事件（检测拖拽）
        function onMouseMove(event) {
            if (mouseDownPosition) {
                const dx = event.clientX - mouseDownPosition.x;
                const dy = event.clientY - mouseDownPosition.y;
                const distance = Math.sqrt(dx * dx + dy * dy);
                
                // 如果移动距离超过阈值，认为是拖拽（增加容错空间，避免误判）
                if (distance > 30) {
                    isDragging = true;
                    // 如果检测到拖拽且有高亮对象，清除引导线和信息框
                    if (highlightedObject) {
                        clearHighlight();
                    }
                }
            }
        }
        
        // 鼠标抬起事件
        function onMouseUp(event) {
            if (mouseDownPosition) {
                mouseDownPosition = null;
            }
        }
        
        // 鼠标点击事件处理
        function onMouseClick(event) {
            // 如果是拖拽，不处理点击
            if (isDragging) {
                isDragging = false;
                isClicking = false;
                return;
            }
            
            isClicking = true;
            
            // 计算鼠标在标准化设备坐标中的位置 (-1 到 +1)
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
            
            // 更新射线
            raycaster.setFromCamera(mouse, camera);
            
            // 获取场景中所有可交互的对象（包括模型及其子对象）
            const objectsToCheck = [];
            scene.traverse((child) => {
                if (child.isMesh && child.visible) {
                    objectsToCheck.push(child);
                }
            });
            
            // 执行射线检测
            const intersects = raycaster.intersectObjects(objectsToCheck, true);
            
            if (intersects.length > 0) {
                // 找到最近的交点对象
                const clickedObject = intersects[0].object;
                const intersectionPoint = intersects[0].point;
                
                highlightObject(clickedObject);
                
                // 将3D世界坐标转换为屏幕坐标
                const vector = intersectionPoint.clone().project(camera);
                const screenX = (vector.x + 1) * window.innerWidth / 2;
                const screenY = (-vector.y + 1) * window.innerHeight / 2;
                
                // 信息框位置（右侧，固定位置，不需要实际获取位置）
                // 信息框在右侧50px处，垂直居中
                const endX = window.innerWidth - 50 - 350; // 右侧50px + 文本框宽度350px
                const endY = window.innerHeight / 2; // 垂直居中
                
                // 保存引导线状态
                currentGuideLineState = {
                    startX: screenX,
                    startY: screenY,
                    endX: endX,
                    endY: endY,
                    useCorner: true,
                    cornerType: 'right' // 可以改为 'acute' (锐角) 或 'obtuse' (钝角)
                };
                
                // 绘制引导线（使用带拐角的线，默认直角）
                drawGuideLine(screenX, screenY, endX, endY, true, 'right');
                
                // 获取并显示部位信息
                const partInfoData = getPartInfo(clickedObject);
                showInfoBox(partInfoData.title, partInfoData.content);
                
                // 输出调试信息（帮助用户配置映射表）
                const objectName = clickedObject.name || '未命名对象';
                console.log('=== 点击对象信息 ===');
                console.log('对象名称:', objectName);
                console.log('对象类型:', clickedObject.type);
                console.log('父对象:', clickedObject.parent?.name || '无');
                console.log('匹配的部位:', partInfoData.title);
                console.log('点击位置:', intersectionPoint);
                console.log('屏幕坐标:', screenX, screenY);
                console.log('==================');
            } else {
                // 点击空白区域，清除高亮
                clearHighlight();
            }
            
            // 记录点击时间
            lastClickTime = Date.now();
            
            // 点击处理完成后，重置标志
            setTimeout(() => {
                isClicking = false;
            }, 200);
        }
        
        // 添加鼠标事件监听
        renderer.domElement.addEventListener('mousedown', onMouseDown);
        renderer.domElement.addEventListener('mousemove', onMouseMove);
        renderer.domElement.addEventListener('mouseup', onMouseUp);
        renderer.domElement.addEventListener('click', onMouseClick);
        
        // 给信息框添加点击事件，点击时清除
        infoBox.addEventListener('click', (event) => {
            event.stopPropagation(); // 阻止事件冒泡
            clearHighlight();
        });
        
        // 窗口大小调整
        window.addEventListener('resize', () => {
            camera.aspect = window.innerWidth / window.innerHeight;
            camera.updateProjectionMatrix();
            renderer.setSize(window.innerWidth, window.innerHeight);
            // 更新引导线画布尺寸
            initGuideLineCanvas();
            // 如果当前有显示的引导线，需要重新绘制
            if (highlightedObject && currentGuideLineState) {
                updateGuideLine();
            }
            // 更新 Tab 滚动按钮状态
            updateScrollButtons();
        });

        // 动画循环
        function animate() {
            requestAnimationFrame(animate);
            controls.update();
            
            // 检测相机位置或目标是否发生变化（用于检测模型的位移或旋转）
            // 排除点击操作后的短暂时间（200ms），避免误判
            const timeSinceClick = Date.now() - lastClickTime;
            if (!isClicking && timeSinceClick > 200 && highlightedObject) {
                // 计算位置和目标的变化距离，增加容错空间
                const positionDistance = camera.position.distanceTo(lastCameraPosition);
                const targetDistance = controls.target.distanceTo(lastControlsTarget);
                
                // 如果位置或目标变化超过阈值（0.5），说明模型发生了明显的位移或旋转
                if (positionDistance > 0.5 || targetDistance > 0.5) {
                    clearHighlight();
                }
            }
            
            // 更新保存的位置和目标
            lastCameraPosition = camera.position.clone();
            lastControlsTarget = controls.target.clone();
            
            // 如果相机位置改变，更新引导线位置
            if (highlightedObject && currentGuideLineState) {
                updateGuideLine();
            }
            
            renderer.render(scene, camera);
        }

        animate();
    </script>
</body>
</html>

